
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// IDGFormInspectorListener
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 * In order to use IDGFormInspector you need to provide an object with implementation of the following methods:
 */
var IDGFormInspectorListener = function ()
{
	/**
	 * Makes a request to the server to save the profile
	 * @param JSON string with the profile information
	 */
	this.saveProfile = function(payload)
	{
	}

	/**
	 * Called when a login form was found or the tick of the username field was clicked. The implementation
	 * usually should popup a dialog with the available profiles for the given host. 
	 * 
	 * @param host the host to show profiles for
	 * @return IDGProfileSelection object
	 */
	this.selectProfile = function(host)
	{
	}

	/**
	 * Fired when the profile is already selected. If one-click login is enabled the form will submitted 
	 * right after this callback. Otherwise the form will be submitted by the user, when he clicks the 
	 * submit button in the web page.
	 * 
	 * @param profileToken the profile token to submit with
	 * @param passwordFieldName the password field name
	 */
	this.formWillSubmit = function(profileToken, passwordFieldName)
	{
	}

	/**
	 * Returns whether one click is enabled or not
	 * @returns {Boolean}
	 */
	this.isOneClickEnabled = function()
	{
	}
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// DTOs
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 * Wraps a profile selection status
 */
var IDGProfileSelection = function(status, username, token) {
	// SelectionStatus constant
	this.status = status;
	// The usename to fill in the username field of the form
	this.username = username;
	// The profile token
	this.token = token;
};

/**
 * Form field descriptor
 */
var IDGPrivacyConnectField = function(id, name, type, value, match) {
	this.id = id
	// name of the field
	this.name = name;
	// type of the field
	this.type = type;
	// value of the field
	this.value = value;
	// string object
	this.match = match;
};

///**
// * Only significant fields in the form have this match rule. It's type is either 'password' or 'username'
// */
//var IDGMatchRule = function(type) {
//	this.field = type;
//};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Constants
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

var SelectionStatus = {
	// No profiles were found for this site
	EMPTY: "EMPTY", 
	// The site has profiles, but the dialog was canceled
	CANCELED: "CANCELED", 
	// Error occurred
	ERROR: "ERROR",
	// The site has profiles and one has been selected
	SELECTED: "SELECTED"
};

var TextFieldTypes = ["text", "email", "url", "tel", "number"];

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// IDGFormInspector
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 * @param listener implementation of IDGFormInspectorListener contract
 */
var IDGFormInspector = function (listener)
{
	// form objects
	this.mForm          = null;
	this.mPasswordField = null;
	this.mUsernameField = null;
	this.mSubmitButton  = null;

	this.mIsLoginForm = false;
	this.mIsRegForm   = false;

	// page attributes
	this.mHost     = window.location.host;
	this.mProtocol = window.location.protocol;
	this.mPath     = window.location.pathname;
	this.mTitle    = document.title;

	// listener attach indicators
	this.mSubmitListenerAttached = false;
	this.mShouldSaveProfile      = true;

	this.mListener = listener;

	/**
	 * Inspects the DOM and if a login form is found it calls IDGFormInspectorListener.selectProfile
	 */
	this.inspectDom = function() {
		var allForms = document.getElementsByTagName("form");

		// get all forms
		for (var formIdx = 0; formIdx < allForms.length; formIdx++) {
			var form = allForms[formIdx];
			if (this.isLoginForm(form)) {
				this.mForm = form;
				break;
			}
		}

		if (this.mIsLoginForm) {
			var profileSelection = this.mListener.selectProfile(this.mHost, this.mUsernameField.id);
			this.handleProfileSelection(profileSelection);
		}
		else if (this.mIsRegForm) {
			// nothing
		}
	};

	/**
	 * Checks whether this is a credible login/register form
	 * @param form the form to check
	 * @returns {Boolean}
	 */
	this.isLoginForm = function(form) {
		var textFieldsCount = 0;
		var passFieldsCount = 0;

		// get all form elements
		for (var i = 0; i < form.elements.length; i++) {
			var field = form.elements[i];
			var type = field.type.toLowerCase();
			var name = field.name.toLowerCase();

			if (type == "password") {
				passFieldsCount++;
				this.mPasswordField = field;

				// find the username field as the first non hidden field, going upwards
				for (var d = i - 1; d >= 0; d--) {
					var tmpField = form.elements[d];
					if (tmpField != null && tmpField.type != "hidden") {
						this.mUsernameField = tmpField;
						break;
					}
				}
			}
			else if (this.isTextField(type)) {
				textFieldsCount++;
			}
			else if (type == "submit" || type == "buttofield type is a text field typen") {
				this.mSubmitButton = field;
			}
		}
		this.mIsLoginForm = passFieldsCount == 1;
		this.mIsRegForm = passFieldsCount > 1 && textFieldsCount > 1;

		return this.mIsLoginForm || this.mIsRegForm;
	};

	/**
	 * Checks whether a given field type is a text field type
	 * @param fieldType
	 * @returns {Boolean}
	 */
	this.isTextField = function(fieldType) {
		for (var type in TextFieldTypes) {
			if (type == fieldType) {
				return true;
			}
		}
		return false;
	};

	/**
	 * Submits this form
	 */
	this.submitForm = function() {
		if (this.mSubmitButton) {
			this.mSubmitButton.click();
		}
		else {
			this.mForm.submit();	
		}
	};

	/**
	 * 
	 * @param profileSelection IDGProfileSelection object
	 */
	this.handleProfileSelection = function(profileSelection) {
		if (profileSelection.status == SelectionStatus.SELECTED) {
			this.mShouldSaveProfile = false;
			// java script doesn't save the context of this
			var pco = this;

			FormDecoration.highlightForm(this.mUsernameField, this.mPasswordField, function() {
				var profileSelection = pco.mListener.selectProfile(pco.mHost, pco.mUsernameField.id);
				pco.handleProfileSelection(profileSelection);
			});

			this.mUsernameField.value = profileSelection.username;
			this.mPasswordField.value = "********";

			this.mListener.formWillSubmit(profileSelection.token, this.mPasswordField.name);

			var enableOneclickLogin = this.mListener.isOneClickEnabled();

//			if (enableOneclickLogin == "true") {
				setTimeout(function() { 
					pco.submitForm();
				}, 1000);
//			}
		}
		else if (profileSelection.status == SelectionStatus.CANCELED) {
			this.mShouldSaveProfile = false;
			this.attachToLoginForm();
		}
		else if (profileSelection.status == SelectionStatus.EMPTY) {
			this.mShouldSaveProfile = true;
			this.attachToLoginForm();
		}
		else if (profileSelection.status == SelectionStatus.ERROR) {
			// TODO ??
		}
	};

	/**
	 * Collects the fields from this login form
	 * @returns an Array of IDGPrivacyConnectField objects
	 */
	this.getFormFieldsToSaveProfile = function() {
		var fields = Array();

		for (var i = 0; i < this.mForm.elements.length; i++) {
			var element = this.mForm.elements[i];
			var matchRule = null;

			if (element == this.mUsernameField) {
				matchRule = "field: username";
			}
			else if (element == this.mPasswordField) {
				matchRule = "field: password";
			}
			var f = new IDGPrivacyConnectField(element.id, element.name, element.type, element.value, matchRule);
			fields.push(f);
		}
		return fields;
	};

	/**
	 * 
	 */
	this.attachToLoginForm = function() {
		if (!this.mSubmitListenerAttached) {
			// java script doesn't save the context of this
			var pco = this;

			var keypressCallback = function() {
				pco.mShouldSaveProfile = true;		
			};
			var submitCallback = function() {
				if (pco.mShouldSaveProfile) {
					var profile = {
						name : pco.mUsernameField.value,
						description : pco.mTitle,
						link : document.URL,
						fields : pco.getFormFieldsToSaveProfile(),
						formUrl : pco.mForm.action,
						formContainerUrl : document.URL
					};
					pco.mListener.saveProfile(profile);
				}
				return true;		
			};

			this.mUsernameField.addEventListener("keypress", keypressCallback);
			this.mPasswordField.addEventListener("keypress", keypressCallback);
			this.mForm.addEventListener('submit', submitCallback, false);
			this.mSubmitListenerAttached = true;
		}
	};

};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Form decoration.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 * Singleton object for form decoration
 */
var FormDecoration = new function() {
	/**
	 * Highlights the username and password fields of a form. It also inserts a tick image inside the username field.
	 * 
	 * @param usernameField the username field
	 * @param passwordField the password field
	 * @param tickClickListener function callback to be added as a 'click' listener to the tick image in the username field.
	 *                          Usually this function should pop up the privacy connect profiles dialog 
	 */
	this.highlightForm = function(usernameField, passwordField, tickClickListener)
	{
		this.highlightField(usernameField);
		this.highlightField(passwordField);
		this.insertTick(usernameField, tickClickListener);
	}

	/**
	 * Puts a green border around the given field
	 * @param field the field to put a border around
	 */
	this.highlightField = function(field)
	{
		field.style.border = '#adff2f 2px solid';
		field.style.borderRadius = '5px 5px 5px 5px';
	}

	/**
	 * Inserts a tick image inside the given input field. 
	 * @param field the field to insert the tick in
	 * @param tickClickListener callback to be registered on 'click'
	 */
	this.insertTick = function(field, tickClickListener)
	{
		var tickId = "idgard_show_profiles_tick_button";

		if (!document.getElementById(tickId)) {
			var imgNode = document.createElement("img");

			imgNode.id = tickId;
			imgNode.src = "https://idgard.itsmyprivacy.de/img/favicon.ico";

			imgNode.style.padding = '0px';
			imgNode.style.width = '14px';
			imgNode.style.height = '19px';
			imgNode.style.cursor = 'pointer';
			imgNode.style.marginLeft = '-16px';
			imgNode.style.display = 'inline';

			imgNode.align = 'absmiddle';
			imgNode.addEventListener("click", tickClickListener, false);

			field.parentNode.insertBefore(imgNode, field.nextSibling);
		}
	}
}
